<?php
	/* -----------------------------------------------------------------
	 * FSHL example
	 */
	
	function GetPostParam($param) {
		return isset($_POST[$param]) ? $_POST[$param] : null;
	}
	
	function LoadFile($filename) {
		$filehandle = fopen ($filename, 'r') or die("Could not open $filename for reading.");
		$text = fread($filehandle, filesize($filename));
		fclose($filehandle);
		return $text;
	}

	function safeFileWrite($file, $mode, &$str) {
		// ceate a lock file - if not possible someone else is active so wait (a while)
		$err = true;
		$lock = $file.'.lock';
		$lf = @fopen ($lock, 'x');
		$i = 0;
		while ($lf === false && $i++ < 20) {
			clearstatcache();
			usleep(rand(5,85));
			$lf = @fopen ($lock, 'x');
		}
		// if lockfile (finally) has been created, file is ours, else give up ...
		if ($lf !== false) {
			$fp = fopen($file, $mode);
			if($fp !== false) {
				fwrite($fp, $str); // or use a callback
				fclose($fp);
				$err = false;
			}
			// and unlock
			fclose($lf);
			unlink($lock);
		}
		return $err;
	}
	
	// -----------------------------------------------------------------
	// Language array (TODO: add new languages here)

	$lang_config = array(

	// index		lang_name		option text

		"1" => array("HTML",		"HTML (with CSS, JS and PHP)"),
		"2" => array("HTMLonly",	"HTML only"),
		"3" => array("CSS",			"CSS only"),
		"4" => array("PHP",			"PHP only"),
		"5" => array("JS",			"JS only"),
		"6" => array("CPP",			"C/C++"),
		"7" => array("JAVA",		"JAVA"),
		"8" => array("TXT",			"TXT (dummy lexer)"),
		"9" => array("RUBY",			"RUBY only"),
	);

	// -----------------------------------------------------------------
	// FSHL DEMO Initialization
	// -----------------------------------------------------------------
	include ('fshl/fshl.php');
	@include('online_limit.php');
	
	if(!defined('FSHL_LIVEDEMO_LIMIT')) {
		define('FSHL_LIVEDEMO_LIMIT', 0x7fffffff);
	}
	
	$start_language = "HTML";

	$user_lang = GetPostParam("lang_type");
	$user_text = GetPostParam("test_text");
	$ln_checked = GetPostParam("line_counter");
	$tabs_checked = GetPostParam("emulate_tabs");
	$nbsp_checked = GetPostParam("use_nbsp");
	$simple_output = GetPostParam("simple_output");
	$text_encoding = GetPostParam("text_encoding");
	$demo = true;
	$lng = 0;
	
	if(!$user_text && !$user_lang && !$ln_checked && !$tabs_checked && !$nbsp_checked) {
		$tabs_checked = $ln_checked = true;
		$nbsp_checked = false;
		$text_encoding = 0;
	}
	
	$js_warning_message = "WARNING: your string is too long for this demo. Max input size is ".FSHL_LIVEDEMO_LIMIT." bytes.";
	
	if($user_text && $user_lang) {
		// process user's text
		if(isset($lang_config[$user_lang])) {
			$start_language = $lang_config[$user_lang][0];
			$text = stripslashes($user_text);
			$filename = "your text";
			if(strlen($text) > FSHL_LIVEDEMO_LIMIT) {
				$w = "\n[[ $js_warning_message ]]\n";
				$text = "$w\n".substr($text, 0, FSHL_LIVEDEMO_LIMIT)."\n$w";
			}
			$lng = strlen($text);
			$demo = false;
		}
	}
	$cache_index = ($text_encoding?0:1).($tabs_checked?0:1).($ln_checked?0:1);
	$cache_file = "demo_cache/$cache_index.txt";
	$cache_results_file = "demo_cache/$cache_index.res.txt";
	$out = false; $write_to_cache = false; $content_is_cached = false;
	if($demo) {
		$filename = 'index.php';				// self read
		if(defined('FSHL_LIVEDEMO_CACHE') && FSHL_LIVEDEMO_CACHE) {
			// fake cache implementation
			@$ts = filemtime($cache_file);
			@$update = 	$ts < filemtime($filename) ||
						$ts < filemtime('fshl/fshl.php') || 
						$ts < filemtime(FSHL_CACHE.'.touch');
			if($ts === FALSE || $update) {
				$write_to_cache = true;
			} else {
				$out = LoadFile($cache_file);
				$tmp = unserialize(LoadFile($cache_results_file));
				$time = $tmp[0]; $lng = $tmp[1];
				$content_is_cached = true;
			}
		}
		if(!$out) {
			$text = LoadFile($filename);
			$lng = strlen($text);
		}
	}
	// -----------------------------------------------------------------
	//                          LET'S GO
	// -----------------------------------------------------------------
	// make options for parser constructor
	$parser_opt = ($tabs_checked ? P_TAB_INDENT : 0) | 
				  ($ln_checked ? P_LINE_COUNTER : 0) | 
				  ($nbsp_checked ? P_USE_NBSP : 0);			// experimental option
				  
	$parser_output_module = $text_encoding ? 'RUBY_HTML_UTF8' : 'RUBY_HTML_UTF8';
	
	// create new parser object	
	$parser = new fshlParser($parser_output_module, $parser_opt);
	
	if(!$demo) {
		// classic highlight example (applied on user's text)
		$out = $parser->highlightString($start_language, $text);
		$time = $parser->getParseTime();
	} else {
		if(!$out) {
			// new 'per partes' highlight example
			$offset = 0;
			while($offset < strlen($text)) {
				$sub_text = substr($text, $offset, 0x666);
				if(!$offset) {
					$counter_padding = $parser->calcCounterPadding($text);
					$out  = $parser->highlightString($start_language, $sub_text, 0, $counter_padding);
					$time = $parser->getParseTime();
				} else {
					$out .= $parser->highlightNextString($sub_text);
					$time += $parser->getParseTime();
				}
				$offset += strlen($sub_text);
			}
		}
	}
	if($write_to_cache) {
		// NOTE: this simple cache method may be very unstable, use at your own risk on live servers
		safeFileWrite($cache_file, 'w', $out);
		safeFileWrite($cache_results_file, 'w', serialize(array($time, $lng)));
	}
	
	// Show results....
	
	//<!-- cohenizator -->
	$encoding_str = $text_encoding ? 'windows-1250' : 'utf-8';
	if($simple_output) {
		include('simple_output.php');
		exit();
	}
	//<!-- /cohenizator -->
	echo "<?xml version=\"1.0\" encoding=\"$encoding_str\"?>\n";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=<?php echo $encoding_str;?>" />
  <title>FastSHL Example - universal syntax highlighter</title>
  <style type="text/css">
  <?php include (FSHL_STYLE.'COHEN_style.css'); ?>
  <?php include (FSHL_STYLE.'RUBY_style.css'); ?>

	BODY 
	{
		font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
		font-size: 80%;
		margin: 2em;
		background: #FFF;
		color: #000;
	}

	H1	{ font-size: 170%;}
	H2	{ font-size: 140%;}
	H3	{ font-size: 120%;}
	H4	{ font-size: 100%;}
	P	{ font-size: 80%;  }

	/* hello fczbkk :) */

	.formular {
		/*width: 600px;*/
		margin: 0px auto;
		border: 2px solid #FFF;
		background-color: #fdc;
		padding: 10px;
	}
	.formular .riadok {
		clear: both;
		margin: 2px auto;
	}

	.formular .riadok .lavy {
		width: 20%;
		float: left;
		text-align: left;
	}
	.formular .riadok .pravy {
		width: 80%;
		float: right;
		text-align: left;
	}
	.formular .tlacitka {
		clear: both;
		text-align: center;
	}
	.formular .foo {
		clear: both;
	}

	.formular .code {
		font-size: 120%;
		clear: both;
		background-color: #fff;
	}

  </style>
  <script type="text/javascript">
	// thanx to johno, for great example;)
	function validate() {
		var elm = document.getElementById('test_text');
		if(elm && (elm.value.length > <?php echo FSHL_LIVEDEMO_LIMIT; ?> + 4)) {
			alert('<?php echo $js_warning_message; ?>');
			return false;
		}
		return true;
	}
  </script>
</head>
<body>
<h2><a href="http://hvge.sk/scripts/fshl">FSHL</a> tester</h2>
<form class="formular" method="post" action="index.php" onsubmit="return validate();">
	<div class="riadok">
		<span class="lavy">Enter your text</span>
		<span class="pravy">
			<textarea name="test_text" id="test_text" cols="60" rows="8">require 'sysvipc'
include SystemVIPC

class EventHelper

  @@temp_dir = File.dirname(__FILE__)+'/events_data/'
  @@helper = {}

  def initialize msg_q_id
    
    #if @@helper[msg_q_id].instance_of? EventHelper
    #  return @@helper[msg_q_id]
    #else
    #  @@helper[msg_q_id] = this
    #end
    
    
    if msg_q_id.nil? then
        raise "Message queue id (the first argument) cannot be nil!"
    end
    @my_msg_q_id = msg_q_id + 1

    #All IPC objects are identified by a key. SystemVIPC includes a convenience function for mapping file names and integer IDs into a key:
    key = ftok(@@temp_dir + 'msg_q', 0)
    #Get (create if necessary) a message queue:
    @msg_q = MessageQueue.new(key, IPC_CREAT | 0600)

    key = ftok(@@temp_dir + 'sh_mem', 1)
    @sh_m_size = 1024*10
    @sh_m = SharedMemory.new(key, @sh_m_size, IPC_CREAT | 0600)
    @sh_m.attach
    
    key = ftok(@@temp_dir + 'sem', 2)
    @sem = Semaphore.new(key, 1, IPC_CREAT | 0600)
    key = ftok(@@temp_dir + 'sem2', 2)
    @sem2 = Semaphore.new(key, 1, IPC_CREAT | 0600)
    if @sem.pid(0) == 0
      @sem.set_value(0, 1)  
    end
    if @sem2.pid(0) == 0
      @sem2.set_value(0, 1)
    end
    subscribers
  end
  
  def my_message_queue_id
    @my_msg_q_id
  end

  def subscribe_array subscribe_array
    #wait until we can reach criticlal section
    @sem.apply [SemaphoreOperation.new(0, -1, SEM_UNDO)]
    s = subscribers
    #s = {}
    subscribe_array.each {|subscription| 
      id = subscription['id'].to_i
      source = subscription['source']
      puts "new subscription to source: "+source.inspect + ", id: " + id.inspect + " msg_q: "+@my_msg_q_id.inspect
      if s[source].nil? then
        s = s.merge!(source => { id => { @my_msg_q_id => Time.now} })
      else
        if s[source][id].nil? then
          s[source].merge!(id => { @my_msg_q_id  => Time.now })
        else
          s[source][id].merge!( @my_msg_q_id => Time.now )
        end        
      end
    }
    @sh_m.write((Marshal.dump(s)))
    #exit critical section
    @sem.apply [SemaphoreOperation.new(0, 1, SEM_UNDO)]
  end
  
  def subscribe source, id
    subscribe_array [ {'source' => source, 'id' => id } ]
  end
  
  def clear_sh_m
    #puts "chci mazat sh_m, čekám na uvolnění semaforu"
    @sem.apply [SemaphoreOperation.new(0, -1, SEM_UNDO)]
    #puts "jsme v kritické sekci"
    @sh_m.write(Marshal.dump({}))
    #exit critical section
    #puts "opouštím kritickou sekci"
    @sem.apply [SemaphoreOperation.new(0, 1, SEM_UNDO)]
    nil
  end
  
  def subscribers
    #@sem2.apply [SemaphoreOperation.new(0, -1, SEM_UNDO)]
    data = @sh_m.read(@sh_m_size)
    #@sem2.apply [SemaphoreOperation.new(0, 1, SEM_UNDO)]
    if ((data.tr "\000", "") != '') then
      Marshal.restore(data)
    else
      {}
    end
  end
  
  def listen wait = true
    puts((wait ? '' : 'not') + "waiting for message at "+@my_msg_q_id.inspect)
    data = Marshal.restore @msg_q.recv(@my_msg_q_id, 1024*2, wait ? nil : IPC_NOWAIT)
    puts "new message!" + data.inspect
    data
  end
  
  def subscribers_for source, id
    s = subscribers
    if !s[source].nil? and !s[source][id].nil?
      s[source][id] 
    end
  end
  
  def fire_event source, id, name, data, destination_msg_q = nil
    puts "wanting to fire an event:"
    id = id.to_i
    data = { 
      :source => source,
      :source_msg_q => @my_msg_q_id,
      :name => name,
      :id => id,
      :data => data,
      :sent => Time.now
      }
    message = Marshal.dump data
    
    puts data.inspect
    
    if (!destination_msg_q.nil?)
      subscribers = { destination_msg_q => Time.now }
    else
      subscribers = subscribers_for source, id
    end
    
    puts subscribers.inspect
    
    if !subscribers.nil? && subscribers != {}
      subscribers.each_key {|msg_q_id|
        puts "sending event to msg_q_id: "+msg_q_id.inspect
        @msg_q.send(msg_q_id, message)
      }
    else
      puts "warning: no one to subsribe fired event"
    end
  end
  
end

class EventHelper::Event
  def initialize info
    if !info[:data].instance_of? Hash
      raise ':data has to be hash!'
    end
    @name = info[:name]
    @source = info[:source]
    @id = info[:id]
    @data = info[:data]
  end
end

</textarea>
		</span>
	</div>

	<div class="riadok">
		<span class="lavy">Text encoding</span>
		<span class="pravy">
			<select name="text_encoding" onchange="this.form.submit();">
				<option value="0" <?php if(!$text_encoding) echo 'selected="selected"';?>>UTF-8</option>
				<option value="1" <?php if( $text_encoding) echo 'selected="selected"';?>>8-bit RAW mode</option>
			</select>			
		</span>
	</div>
	<div class="riadok">
		<br />
		<span class="lavy">Select language</span>
		<span class="pravy">
			<select name="lang_type">
<?php
			foreach($lang_config as $index => $language)
			{
				echo "\t\t\t\t<option ";
				if($index == $user_lang)
					echo 'selected="selected" ';
				echo "value=\"".$index."\">".$language[1]."</option>\n";
			}
?>
			</select>
		</span>
	</div>
	
	<div class="riadok">
		<span class="lavy">Additional parser options</span>
		<span class="pravy">			
			<input type="checkbox" name="line_counter" <?php if($ln_checked) echo 'checked="checked"';?> />
				Show line numbers<br />
			<input type="checkbox" name="emulate_tabs" <?php if($tabs_checked) echo 'checked="checked"';?> />
				Emulate tabs<br />
			<input type="checkbox" name="use_nbsp" <?php if($nbsp_checked) echo 'checked="checked"';?> />
				Use &amp;nbsp; insead space char<br />
		</span>
	</div>
	
	<div class="riadok">
		<span class="pravy">
			<br />
			<input type="submit" value="Highlight" />
			<input type="checkbox" name="simple_output" <?php if($simple_output) echo 'checked="checked"';?> /> 
				Download file (simple output)
		</span>
	</div>
	
	<div class="foo">
	</div>
</form>

<div class="formular">
	<h2><?php echo ($content_is_cached ? 'Cached results' : 'Results').($demo ? " (demo - '$filename')" : null); ?></h2>
	<div class="riadok">
		<span class="lavy">FSHL Version</span>
		<span class="pravy"><?php echo "<strong>".FSHL_PARSER_VERSION."</strong>"; ?></span>
	</div>
	<div class="riadok">
		<span class="lavy">Input filename</span>
		<span class="pravy"><?php 	
			echo "<strong>$filename</strong> ($lng bytes / output ".strlen($out).' bytes)'; 
									
		?></span>
	</div>
	<div class="riadok">
		<span class="lavy">PARSE time</span>
		<span class="pravy"><?php printf("<strong>%0.3f</strong> sec (%0.2f kB/s)", $time, $lng/$time/1024 ); ?></span>
	</div>

	<div class="code">
		<pre class="normal"><?php echo $out; ?></pre>
	</div>
</div>
</body>
</html>
